﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

namespace wicFrac
{
    public partial class FreeFormBox : UserControl
    {
        /// <summary>
        /// the outline of the FreeFormBox
        /// </summary>
        protected GraphicsPath RegionGp;
        /// <summary>
        /// the control handles for manipulating the shape of FreeFormBox contain 9 segments, see GenerateControlPaths
        /// </summary>
        protected GraphicsPath[] ControlPaths;
        /// <summary>
        /// [0] is point of cursor, [1] is point of rectangle's center
        /// </summary>
        protected Point[] MouseDownPoints;
        Pen MyPen;

        public void InitializeTools()
        {
            RegionGp = new GraphicsPath();
            MyPen = new Pen(Color.Black, 1);
        }
        public FreeFormBox(Rectangle r)
        {
            InitializeComponent();
            InitializeTools();
            RegionGp.AddRectangle(r);
            UpdateRegion();
        }
        /// <summary>
        /// update region from RegionGp and generate new controlpaths
        /// </summary>
        /// <param name="?"></param>
        public void UpdateRegion()
        {
            GraphicsPath gp = RegionGp.Clone() as GraphicsPath;
            
            gp.Widen(MyPen);
            Region = new Region(gp);
            GenerateControlPaths();
        }
        public FreeFormBox()
        {
            InitializeComponent();
            InitializeTools();
            RegionGp.AddRectangle(new Rectangle());
            UpdateRegion();
        }

        private void FreeFormBox_Load(object sender, EventArgs e)
        {
            
            
        }
        
        protected override void OnPaint(PaintEventArgs e)
        {
            if (Focused)
            {
                DrawControlPaths();
            }
            else
            {
                
            }
            DrawBorder();
            //base.OnPaint(e);
        }
        protected void DrawBorder()
        {
            Graphics g = CreateGraphics();
            g.Clear(BackColor);
            g.DrawPath(MyPen, RegionGp);
            g.Flush();
            
        }
        protected void DrawControlPaths()
        {
            Graphics g = CreateGraphics();
            foreach (GraphicsPath gp in ControlPaths)
                g.DrawPath(MyPen, gp);
                
        }
        /// <summary>
        /// generate control paths according to current RegionGp
        /// </summary>
        protected void GenerateControlPaths()
        {
            ControlPaths = new GraphicsPath[9];
            

            RectangleF rf = RegionGp.GetBounds();
            PointF[,] grid = new PointF[4,4];
            float pad = 0.1F;
            SizeF space = new SizeF(rf.Width * pad, rf.Height * pad);
            grid[0, 0] = rf.Location; grid[0, 1] = PointF.Add(rf.Location, space); grid[0, 2] = new PointF(rf.Right - rf.Width * pad, rf.Top); grid[0, 3] = new PointF(rf.Right, rf.Top);
            grid[1, 0] = new PointF(rf.Left, rf.Top + rf.Height * pad); grid[1, 1] = PointF.Add(rf.Location, space); grid[1, 2] = new PointF(grid[0, 2].X, grid[1, 0].Y); grid[1, 3] = PointF.Add(grid[0, 2], space);
            grid[2, 0] = new PointF(rf.Left, rf.Bottom - rf.Height * pad); grid[2, 1] = new PointF(grid[1, 1].X, grid[2, 0].Y); grid[2, 2] = new PointF(grid[1, 2].X, grid[2, 0].Y); grid[2, 3] = new PointF(rf.Right, grid[2, 0].Y);
            grid[3, 0] = new PointF(rf.Left, rf.Bottom); grid[3, 1] = PointF.Add(grid[2, 0], space); grid[3, 2] = new PointF(grid[2, 2].X, rf.Bottom); grid[3, 3] = PointF.Add(grid[2, 2], space);
            ControlPaths[0] = new GraphicsPath();
            ControlPaths[0].AddPolygon(new PointF[] { grid[0, 0],grid[0, 1],grid[1, 1], grid[1, 0] });
            ControlPaths[1] = new GraphicsPath();
            ControlPaths[1].AddPolygon(new PointF[] { grid[0, 1],grid[0, 2],grid[1, 2], grid[1, 1] });
            ControlPaths[2] = new GraphicsPath();
            ControlPaths[2].AddPolygon(new PointF[] { grid[0, 2],grid[0, 3],grid[1, 3], grid[1, 2] });
            ControlPaths[3] = new GraphicsPath();
            ControlPaths[3].AddPolygon(new PointF[] { grid[1, 0],grid[1, 1],grid[2, 1], grid[2, 0] });
            ControlPaths[4] = new GraphicsPath();
            ControlPaths[4].AddPolygon(new PointF[] { grid[1, 1],grid[1, 2],grid[2, 2], grid[2, 1] });
            ControlPaths[5] = new GraphicsPath();
            ControlPaths[5].AddPolygon(new PointF[] { grid[1, 2],grid[1, 3],grid[2, 3], grid[2, 2] });
            ControlPaths[6] = new GraphicsPath();
            ControlPaths[6].AddPolygon(new PointF[] { grid[2, 0],grid[2, 1],grid[3, 1], grid[3, 0] });
            ControlPaths[7] = new GraphicsPath();
            ControlPaths[7].AddPolygon(new PointF[] { grid[2, 1],grid[2, 2],grid[3, 2], grid[3, 1] });
            ControlPaths[8] = new GraphicsPath();
            ControlPaths[8].AddPolygon(new PointF[] { grid[2, 2],grid[2, 3],grid[3, 3], grid[3, 2] });
        }
        protected int IdentifyControlRegion(Point onClient)
        {
            Graphics g = CreateGraphics();
            int i = 0;
            for (; i < 9; i++)
                if (RegionGp.IsVisible(onClient, g))
                    return i;
            return -1;
        }

        private void FreeFormBox_MouseHover(object sender, EventArgs e)
        {

        }

        private void FreeFormBox_MouseMove(object sender, MouseEventArgs e)
        {
            if (Focused)
            {
                switch (IdentifyControlRegion(e.Location))
                {

                    case 8:
                    case 0: Cursor = Cursors.SizeNESW; break;
                    case 1:
                    case 7: Cursor = Cursors.SizeNS; break;
                    case 2:
                    case 6: Cursor = Cursors.SizeNWSE; break;
                    case 3:
                    case 5: Cursor = Cursors.SizeWE; break;
                    case 4: Cursor = Cursors.SizeAll; break;
                    case -1:
                    default: Cursor = Cursors.Default; break;

                }
            }
            
        }

        private void FreeFormBox_MouseDown(object sender, MouseEventArgs e)
        {

        }

        private void FreeFormBox_Click(object sender, EventArgs e)
        {
            this.Focus();
        }

        private void FreeFormBox_Enter(object sender, EventArgs e)
        {
            DrawControlPaths();
            Update();
        }

        private void FreeFormBox_Leave(object sender, EventArgs e)
        {
            DrawBorder();
        }
    }
}
